#include "atom.h"
#include "atommutex.h"
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>


static const pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;

uint8_t atomMutexCreate(ATOM_MUTEX* mutex)
{
	
	uint8_t ret = ATOM_OK;

	/* Parameter check */
	if (mutex == NULL)
	{
		/* Bad mutex pointer */
		ret = ATOM_ERR_PARAM;
	}
	else
	{
		pthread_mutex_t* pmutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
		*pmutex = init_mutex;
		mutex->save_ptr = (POINTER)pmutex;

	}

	return ret;
}

uint8_t atomMutexDelete(ATOM_MUTEX* mutex)
{
	uint8_t ret = ATOM_ERROR;

	/* Parameter check */
	if (mutex == NULL)
	{
		/* Bad mutex pointer */
		ret = ATOM_ERR_PARAM;
	}
	else
	{
		pthread_mutex_t* pmutex = mutex->save_ptr;
		int result = pthread_mutex_destroy(pmutex);
		free(pmutex);
		if (result == 0) ret = ATOM_OK;
	}

	return ret;
}

uint8_t atomMutexGet(ATOM_MUTEX* mutex, int32_t timeout)
{
	uint8_t ret = ATOM_ERROR;

	/* Parameter check */
	if (mutex == NULL)
	{
		/* Bad mutex pointer */
		ret = ATOM_ERR_PARAM;
	}
	else
	{
		pthread_mutex_t* pmutex = mutex->save_ptr;
		if (timeout > 0) {
			struct timespec ts;
			clock_gettime(CLOCK_REALTIME, &ts);

			long tick_ns = (1000000000 / SYSTEM_TICKS_PER_SEC);
			long sec = timeout / SYSTEM_TICKS_PER_SEC;
			long nsec = (timeout % SYSTEM_TICKS_PER_SEC) * tick_ns;

			ts.tv_sec += sec;
			ts.tv_nsec += nsec;
			int result = pthread_mutex_timedlock(pmutex, &ts);
			if ( result == ETIMEDOUT) {
				ret = ATOM_TIMEOUT;
			}
			else if( result == 0) {
				result = ATOM_OK;
			}			
		}
		else {
			if (pthread_mutex_lock(pmutex) == 0) {
				ret = ATOM_OK;
			}
		}
	}

	return ret;
}

uint8_t atomMutexPut(ATOM_MUTEX* mutex)
{
	uint8_t ret = ATOM_OK;

	/* Parameter check */
	if (mutex == NULL)
	{
		/* Bad mutex pointer */
		ret = ATOM_ERR_PARAM;
	}
	else
	{
		pthread_mutex_t* pmutex = mutex->save_ptr;
		if (pthread_mutex_unlock(pmutex) == 0) {
			ret = ATOM_OK;
		}
	}

	return ret;
}